/*
 * Store.java
 *
 * Created on 2007年10月9日, 下午8:18
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package com.gzit.store;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;

import android.content.ContentValues;
import android.database.Cursor;

/**
 * 持久化类的基类。遵循的约定： <br>
 * 1.所有的JAVABEAN FIELD设定为public。<br>
 * 2.存储的字段类型接受Integer、Long、Float、String<br>
 * 3.
 * 
 * @todo <br>
 *       1.是否有必要增加其它数据类型的支持 <br>
 *       2.在javabean类加载的时候注册到数据层中<br>
 *       StoreManager.regStores(Account.DUMY, Config.DUMY);
 * 
 * @author teddy
 */
public abstract class Store implements Serializable {

	// //////////////////////////////////
	// 数据的列类型...
	public static final int INT = 0;
	public static final int DOUBLE = 1;
	public static final int FLOAT = 2;
	public static final int STRING = 3;
	public static final int SHORT = 4;

	// 从cursor中获得特定列的数据
	public static Object getColFromCursor(Cursor cursor, int col, int type) {
		switch (type) {
		case INT:
			return cursor.getInt(col);
		case DOUBLE:
			return cursor.getDouble(col);
		case FLOAT:
			return cursor.getFloat(col);
		case SHORT:
			return cursor.getShort(col);
		case STRING:// 默认以字符串的形式返回
		default: {
			return cursor.getString(col);
		}

		}

	}

	// /////////////////////////////
	private static final String[] EMPTY_STRING_ARRAY = new String[0];

	// 子类可以通过覆盖该方法提供交表之后的语句
	public String getPostCreatSQL() {
		return null;
	}

	// 是不是被持久存储保存过
	public boolean isPersisted() {
		return this.rid != -1;
	}

	// 获得列信息
	public String[] getCOLS() {
		return StoreManager.getCOLS(this.getStoreName());
	}

	// 生成库的列
	public String[] genCOLS() {
		ArrayList<String> arrCols = new ArrayList<String>();
		Field[] fields = this.getClass().getFields();

		for (Field f : fields) {
			String name = f.getName();
			if (!Modifier.isStatic(f.getModifiers())) {
				arrCols.add(name);
			}
		}
		return arrCols.toArray(EMPTY_STRING_ARRAY);

	}

	// 获得建表语句
	/*
	 * 获得建表脚本 ：只系统启动时执行一次，这个通过反射没有问题
	 */
	public String getCreateSQL() {

		// NOTE：android的sqllite主键必须是INTEGER类型，就是LONG类型的都不行
		// (20130106这个还需要跟踪下，在后面的android版本其它主键的类型也是可以的)
		StringBuffer sb = new StringBuffer("CREATE TABLE "
				+ this.getStoreName()
				+ "( rid INTEGER PRIMARY KEY AUTOINCREMENT ");
		Field[] fields = this.getClass().getFields();

		for (Field f : fields) {

			// NOTE:不是静态对象域才进行存储操作
			// 并且数据库中只存储int long和string几种类型，基本够用了
			String name = f.getName();
			if (!"rid".equals(name) && !Modifier.isStatic(f.getModifiers())) {

				Class<?> clazz = f.getType();
				if (clazz.equals(Integer.class)) {
					sb.append("," + name + " INTEGER");
					continue;
				}

				if (clazz.equals(Long.class)) {
					sb.append("," + name + " LONG");
					continue;

				}
				if (clazz.equals(Float.class)) {
					sb.append("," + name + " FLOAT");
					continue;
				}

				if (clazz.equals(Double.class)) {
					sb.append("," + name + " DOUBLE");
					continue;
				}

				if (clazz.equals(String.class)) {
					sb.append("," + name + " TEXT");
					continue;
				}

			}

		}

		sb.append(")");

		return sb.toString();

	}

	// 获得存储的名称
	// 默认情况下就是类名
	public String getStoreName() {
		return this.getClass().getSimpleName();
	}

	/*
	 * // 获得入库的数据 // NOTE：通过反射来获得入库单数据，子类可以覆盖该方法，通过直接设置数据的方式，以获得更优的性能
	 * 此机制情况下，前提是所有的对象域都必须是public的，如果是protected与private的子类只能自己负责参数的设置
	 * 
	 * @return
	 * 
	 * @throws Exception
	 */

	public ContentValues getValues() throws Exception {
		ContentValues values = new ContentValues();

		Field[] fields = this.getClass().getFields();
		for (Field f : fields) {

			String name = f.getName();

			if (!"rid".equals(name) && !Modifier.isStatic(f.getModifiers())) {
				Class<?> clazz = f.getType();
				Object v = f.get(this);

				if (clazz.equals(Integer.class)) {
					values.put(name, v == null ? null : (Integer) v);
					continue;
				}

				if (clazz.equals(Long.class)) {
					values.put(name, v == null ? null : (Long) v);
					continue;
				}

				if (clazz.equals(Float.class)) {
					values.put(name, v == null ? null : (Float) v);
					continue;
				}

				if (clazz.equals(Double.class)) {
					values.put(name, v == null ? null : (Double) v);
					continue;
				}

				if (clazz.equals(String.class)) {
					values.put(name, v == null ? null : (String) v);
					continue;
				}

			}

		}
		return values;

	}

	// 数据库中获得的ContentValues放回各个字段中
	public void setValues(Cursor c) throws Exception {

		// 只取得本类中的Field不包括父类的
		Field[] fields = this.getClass().getFields();

		for (Field f : fields) {
			String name = f.getName();
			int cindex = c.getColumnIndex(name);
			if (cindex != -1 && !Modifier.isStatic(f.getModifiers())) {
				Class<?> clazz = f.getType();
				if (clazz.equals(Integer.class)) {
					f.set(this, c.getInt(cindex));
					continue;
				}

				if (clazz.equals(Long.class)) {
					f.set(this, c.getLong(cindex));
					continue;
				}

				if (clazz.equals(Float.class)) {
					f.set(this, c.getFloat(cindex));
					continue;
				}

				if (clazz.equals(Double.class)) {
					f.set(this, c.getDouble(cindex));
					continue;
				}

				if (clazz.equals(String.class)) {
					f.set(this, c.getString(cindex));
					continue;
				}

			}

		}

	}

	public void setRid(Long rid) {
		this.rid = rid;
	}

	// 该对象在数据库中的对应的记录id
	// 为 -1 则说明对象为持久存储过
	public Long rid = -1L;

	public Long getRid() {
		return rid;
	}

	public void removeByCondition(String conditionString) throws Exception {
		StoreManager.deleteByCondition(this, conditionString);
	}

	// 存储对象本身
	public void store() throws Exception {
		StoreManager.insert(this);
	}

	// 删除对象本身
	public void remove() throws Exception {
		StoreManager.delete(this);
	}

	public void update() throws Exception {
		StoreManager.update(this);

	}

}
